(function () {
    function Promise(excutor) {
        const that = this;
        this.status = 'pending'
        this.data = null
        this.callbacks = []
        function resolve(value) {
            if (that.status != 'pending') {
                return
            }
            that.data = value;
            that.status = 'resolved'
            if (that.callbacks.length) {
                that.callbacks.forEach(item => {
                    setTimeout(() => {
                        item.onResolved(value)
                    }, 0)
                })
            }
        }

        function reject(err) {
            if (that.status != 'pending') {
                return
            }
            that.data = value;
            that.status = 'rejected'
            if (that.callbacks.length) {
                that.callbacks.forEach(item => {
                    setTimeout(() => {
                        item.onRejected(err)
                    }, 0)
                })
            }
        }
        excutor(resolve, reject)
    }

    Promise.prototype.then = function (onResolved, onRejected) {
        onResolved = typeof onResolved === 'function' ? onResolved : value => value;
        onRejected = typeof onRejected === 'function' ? onRejected : err => {
            throw err
        }
        const that = this;
        return new Promise((resolve, reject) => {
            function handle(callback) {
                try {
                    const result = callback(that.data)
                    if (result instanceof Promise) {
                        result.then(
                            value => resolve(value),
                            err => reject(err)
                        )
                    } else {
                        resolve(result)
                    }
                } catch (err) {
                    reject(err)
                }
            }
            if (that.status === 'pending') {
                that.callbacks.push({
                    onResolved() {
                        handle(onResolved)
                    },
                    onRejected() {
                        handle(onRejected)
                    }
                })
            } else if (that.status === 'resolved') {
                setTimeout(function () {
                    handle(onResolved)
                }, 0)
            } else {
                setTimeout(function () {
                    handle(onRejected)
                }, 0)
            }
        })
    }

    Promise.prototype.catch = function (onRejected) {
        this.then(undefined, onRejected)   
    }

    Promise.resolve = function (value) {
        return new Promise((resolve, reject) => {
            if (value instanceof Promise) {
                value.then(
                    value => resolve(value),
                    err => reject(err)
                )
            } else {
                resolve(value)
            }
        })
    }

    Promise.reject = function (err) {
        return new Promise((resolve, reject) => {
            reject(err)
        })
    }

    window.Promise = Promise
})(window)